package com.wmx.hb.mapper;

import com.wmx.hb.mapper.provider.Dept2SqlProvider;
import com.wmx.hb.pojo.Dept;
import com.wmx.hb.pojo.Emp;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;

import java.util.List;
import java.util.Map;

/**
 * Mybatis 注解版-核心注解
 * 1、每个 Mapper 接口中的方法名称不允许重复，必须唯一。
 * 2、XxxMapper 接口可以在对应 xml Sql 映射的同时，也可以直接使用注解方式编写 Sql。
 *
 * @author wangMaoXiong
 * @version 1.0
 * @date 2022/6/4 11:41
 */
@Mapper
public interface Dept2Mapper {

    /**
     * 根据部门编号查询部门信息
     * 1、Results 用于映射结果的列与属性，不显示配置时，默认自动映射，映射不上的，值默认为 null.
     * 2、property 是实体的属性名称，或者 Map 的 key 。
     * 3、column 是表中的列名，即 dept 中的列名。存在关联关系时，它的值将作为参数传给 @One、@Many 关联的查询方法作为新的参数值.
     * 4、id 表示此列是否为主键，通常可以不写。
     * 5、javaType 表示 Java 数据类型，通常可以不写，即便是一对多时，也可以不写，都会自动识别。
     * 6、many：表示一对多，select 指定关联查询的方法名称，此时调用者 column 列的值会作为参数传给被调用方法。
     * * 如果是本类中的其它方法，则可以直接写方法名称，否则需要全限定类名.
     * 7、one：表示一对一，用法与 many 相同。
     *
     * @param deptno
     * @return
     */
    @Results(id = "loadDeptByNo", value = {
            @Result(property = "deptNo", column = "deptno", id = true),
            @Result(property = "dName", column = "dname"),
            @Result(property = "empList", column = "deptno", javaType = List.class,
                    many = @Many(select = "com.wmx.hb.mapper.Dept2Mapper.loadEmpByDeptno", fetchType = FetchType.DEFAULT))
    })
    @Select(value = {"select * from dept where deptno=#{deptno}"})
    Map<String, Object> loadDeptByNo(@Param("deptno") Integer deptno);

    /**
     * 根据部门名称模糊查询
     * 1、ResultMap 引用的其它 Results 的 id 值，表示和它们结果映射相同。
     *
     * @param dname ：关键字
     * @return
     */
    @ResultMap(value = {"loadDeptByNo"})
    @Select(value = {"select * from dept where dname like concat('%',concat(#{dname},'%')) "})
    List<Map<String, Object>> loadDeptByName(@Param("dname") String dname);

    /**
     * 根据部门编号查询员工信息
     * Results 不显示配置时，默认自动映射，映射不上的，值默认为 null.
     * 1、useCache：是否缓存本次查询结果，以提高下次查询速度，默认为 true。
     * 2、flushCache：缓存刷新策略：false：不刷新，true：刷新，DEFAULT(默认)：select 语句为 false，insert、update、delete 为 true
     * 3、timeout：缓存时间，单位秒
     *
     * @param deptno
     * @return
     */
    @Select(value = {"select * from emp where deptno=#{deptno}"})
    @Options(useCache = true, flushCache = Options.FlushCachePolicy.FALSE, timeout = 101000)
    List<Map<String, Object>> loadEmpByDeptno(@Param("deptno") Integer deptno);

    /**
     * 根据员工名称模糊查询
     * 1、<script> 标签：表示内容里面可以使用原生的 Mybatis 标签及其语法。
     * 2、使用此标签之后，可以将 xml 映射文件中的内容原封不动的拷贝过来即可使用。
     * 3、如下所示，如果 ename 不为空，则拼接 like 条件，否则拼接 1=2 .
     *
     * @param ename
     * @return
     */
    @Select(value = {"<script>select * from emp <where> <choose> <when test=\"ename !=null and ename !=''\">ename like concat('%',concat(#{ename},'%'))</when><otherwise>1=2</otherwise></choose> </where></script>"})
    List<Emp> loadEmpByName(@Param("ename") String ename);

    /**
     * 新增部门信息
     * 1、useGeneratedKeys：是否返回使用JDBC 3.0支持的自动生成的主键。数据插入后，自动生成的值会自动赋给入参对象的 keyProperty 属性。
     * * 入参对象是 Map 时，同样能赋值
     * 2、keyProperty：对象属性名称，多个时逗号隔开
     * 3、keyColumn：表中的自动增长的列名，多个时逗号隔开
     *
     * @param dept
     * @return ：返回值默认是影响的条数
     */
    @Options(useGeneratedKeys = true, keyProperty = "deptno", keyColumn = "deptno")
    @Insert(value = {"insert into dept(dname,loc) values(#{dname},#{loc})"})
    int addDept(Dept dept);

    /**
     * 入参对象是 Map 时，同样能赋值
     *
     * @param dept
     * @return
     */
    @Options(useGeneratedKeys = true, keyProperty = "deptno", keyColumn = "deptno")
    @Insert(value = {"insert into dept(dname,loc) values(#{dname},#{loc})"})
    int addDept2(Map<String, Object> dept);

    /**
     * 更新部门信息
     * 最后形成的 SQL 语句如：UPDATE dept t SET t.dname=?,t.loc=? WHERE t.deptno=?
     *
     * @param tableName ：被更新的表名
     * @param dept      ：部门信息
     * @return ：返回 update 影响的条数
     */
    @Update({"UPDATE ${tableName} t ", "SET t.dname=#{dept.dname},t.loc=#{dept.loc}", "WHERE t.deptno=#{dept.deptno}"})
    int updateDept(@Param("tableName") String tableName, @Param("dept") Dept dept);

    /**
     * 更新部门信息
     * 1、@UpdateProvider 指定关联的方法，然后在目标方法中编写 Sql 再返回。
     * 2、type：指定关联方法所在的 类
     * 3、method：指定用于提供 SQL 的方法。
     *
     * @param tableName ：被更新的表名
     * @param dept      ：部门信息
     * @return ：返回 update 影响的条数
     */
    @UpdateProvider(type = Dept2SqlProvider.class, method = "updateDept2")
    int updateDept2(@Param("tableName") String tableName, Map<String, Object> dept);

    /**
     * 根据主键删除部门信息
     * 最终生成的 SQL 如：DELETE FROM dept WHERE deptno IN ( ? , ? , ? , ? )
     *
     * @param tableName
     * @param deptnoList
     * @return
     */
    @Delete({"<script>", "DELETE FROM ${tableName} WHERE deptno IN", "<foreach collection='deptnoList' item='deptno' open='(' separator=',' close=')'>", "#{deptno}", "</foreach>", "</script>"})
    int deleteDept(@Param("tableName") String tableName, @Param("deptnoList") List<String> deptnoList);


}
